/*
	Copyright (c) 2012 by karmaleaving@qq.com. All rights RESERVED.
*/

#ifndef __MATH_METHEMATICS_H_VERSION_KL__
#define __MATH_METHEMATICS_H_VERSION_KL__

#include "config.h"
#include <math.h>

KL_BEGIN

#define KL_M_PI 3.1415926535897932384626433832795
#define KL_M_E  2.7182818284590452353602874713527
#define KL_M_1_E 0.36787944117144232159552377016146
#define KL_MAX_EXP 710

class Math
{
public:	
	template<typename Number>
	static Number abs(Number const &val)
	{
		if(val < 0) return -val;
		return val;
	}
	static float ceil(float const &val)
	{
		return ::ceilf(val);
	}
	static double ceil(double const &val)
	{
		return ::ceil(val);
	}	
	static double floor(double const &val)
	{
		return ::floor(val);
	}
	static float floor(float const &val)
	{
		return ::floorf(val);
	}
	// power and logarithm
	static double exp(double const &x)
	{
		return ::exp(x);
	}
	static float exp(float const &x)
	{
		return ::expf(x);
	}
#ifdef _USE_KL_MATH
	static double _exp(double const &x)
	{
		if(x > 1.0 / KL_M_E)
		{
			double result = _exp(x/2);
			return result * result;
		}
		else
		{			
			double result = 1;
			double term = 1; /* (x^N)/N! */
			for(int i = 1; i <= 12 ; ++i)
			{
				result += (term *= x / i);
			}			
			return result;
		}
	}
#endif
	static double pow(double const &base, double const &times)
	{
		return ::pow(base, times);
	}
	static float pow(float const &base, float const &times)
	{
		return ::powf(base, times);
	}
	template<typename Float>
	static Float square(Float const &base)
	{
		return base * base;
	}
	static double square_root(double const &val)
	{
		return ::sqrt(double(abs(val)));
	}
	static float square_root(float const &val)
	{
		return ::sqrtf(val);
	}
	template<typename Float>
	static Float cube(Float const &base)
	{
		return base * base * base;
	}
	static double log10(double const &val)  // common logarithm
	{
		return ::log10(double(val));
	}
	static float log10(float const &val)
	{
		return ::log10f(val);
	}
	static double loge(double const &val)  // natural logarithm
	{
		return ::log(double(val));
	}
	static float loge(float const &val)
	{
		return ::logf(val);
	}
	template<typename Float>
	static Float log(Float const &under, Float const &val)  // logarithm
	{
		return loge(val) / loge(under);
	}
	// trigonometric function
	template<typename Float>
	static Float deg2rad(Float const &angle)
	{
		return angle * (Float(KL_M_PI) / Float(180.0));
	}
	template<typename Float>
	static Float rad2deg(Float const &radian)
	{
		return radian * (Float(180.0) / Float(KL_M_PI));
	}
	static double sin(double const &rad)
	{
		return ::sin(rad);
	}
	static float sin(float const &rad)
	{
		return ::sinf(rad);
	}
	static double cos(double const &rad)
	{
		return ::cos(rad);
	}
	static float cos(float const &val)
	{
		return ::cosf(val);
	}
	static double sinh(double const &val)
	{
		return ::sinh(val);
	}
	static float sinh(float const &val)
	{
		return ::sinhf(val);
	}
	static double cosh(double const &val)
	{
		return ::cosh(val);
	}
	static float cosh(float const &val)
	{
		return ::coshf(val);
	}
	static double tanh(double const &val)
	{
		return ::tanh(val);
	}
	static float tanh(float const &val)
	{
		return ::tanhf(val);
	}
	static double acos(double const &val)
	{
		return ::acos(val);
	}
	static float acos(float const &val)
	{
		return ::acosf(val);
	}
	static double asin(double const val)
	{
		return ::asin(val);
	}
	static float asin(float const &val)
	{
		return ::asinf(val);
	}
	static double atan(double const &val)
	{
		return ::atan(val);
	}
	static float atan(float const &val)
	{
		return ::atanf(val);
	}
};
#endif // __MATH_METHEMATICS_H_VERSION_KL__
KL_END
